package com.health.warehouse.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.health.api.client.UserClient;
import com.health.api.model.hospital.GetHospitalInfoRequest;
import com.health.api.model.hospital.HospitalVO;
import com.health.common.auth.service.TokenService;
import com.health.common.common.ErrorCode;
import com.health.common.exception.BusinessException;
import com.health.common.model.user.LoginUser;
import com.health.warehouse.mapper.WarehouseMapper;
import com.health.api.model.transporter.AddWareHouseItemRequest;
import com.health.warehouse.model.dto.AddWareHouseRequest;
import com.health.warehouse.model.dto.MedicineTransferRequest;
import com.health.warehouse.model.dto.linkItemToWareHouseRequest;
import com.health.warehouse.model.entity.Medicinetransfer;
import com.health.warehouse.model.entity.Warehouse;
import com.health.warehouse.model.entity.WarehouseItems;
import com.health.warehouse.model.enums.WareHouseStatusEnum;
import com.health.warehouse.model.vo.WarehouseItemVO;
import com.health.warehouse.service.MedicinetransferService;
import com.health.warehouse.service.WarehouseItemsService;
import com.health.warehouse.service.WarehouseService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

import static com.health.common.constant.UserConstant.HOSPITAL_ID;
import static com.health.common.constant.UserConstant.HospitalNotFound;
import static com.health.common.constant.WareHouseConstants.*;

/**
 * @author zhexueqi
 * @description 针对表【warehouse(仓库表)】的数据库操作Service实现
 * @createDate 2024-09-01 15:35:27
 */
@Service
public class WarehouseServiceImpl extends ServiceImpl<WarehouseMapper, Warehouse>
        implements WarehouseService {

    @Resource
    private WarehouseItemsService warehouseItemsService;

    @Resource
    private UserClient userClient;

    @Resource
    private TokenService tokenService;

    @Resource
    private MedicinetransferService medicinetransferService;



    @Override
    public boolean addWareHouse(AddWareHouseRequest addWareHouseRequest) {
        QueryWrapper<Warehouse> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(WAREHOUSE_NAME, addWareHouseRequest.getWarehouseName());
        queryWrapper.eq(HOSPITAL_ID, addWareHouseRequest.getHospitalId());
        long count = this.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.WAREHOUSE_EXIST);
        }
        Warehouse warehouse = new Warehouse();
        BeanUtils.copyProperties(addWareHouseRequest, warehouse);
        boolean save = this.save(warehouse);
        if (!save) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addWareHouseItem(AddWareHouseItemRequest addWareHouseItemRequest) {
        // 判断医院是否存在
        HospitalVO hospitalInfo = getHospitalInfoById(addWareHouseItemRequest.getHospitalId());
        if (hospitalInfo == null) {
            throw new BusinessException(ErrorCode.HOSPITAL_NOT_EXIST);
        }

        // 判断批号是否重复
        QueryWrapper<WarehouseItems> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(HOSPITAL_ID, addWareHouseItemRequest.getHospitalId());
        long count = warehouseItemsService.count(queryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }

        // 新增库存
        WarehouseItems warehouseItems = new WarehouseItems();
        BeanUtils.copyProperties(addWareHouseItemRequest, warehouseItems);
        boolean save = warehouseItemsService.save(warehouseItems);
        if (!save) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean linkItemToWareHouse(linkItemToWareHouseRequest linkItemToWareHouseRequest) {
        // 判断仓库是否存在
        Warehouse warehouse = getWareHouseById(linkItemToWareHouseRequest.getWarehouseId());
        if (warehouse == null) {
            throw new BusinessException(ErrorCode.WAREHOUSE_NOT_EXIST);
        }

        // 判断仓库是否可用
        if (warehouse.getStatus() != WareHouseStatusEnum.NORMAL) {
            throw new BusinessException(ErrorCode.WAREHOUSE_NOT_AVAILABLE);
        }

        // 判断物品是否存在
        WarehouseItems warehouseItems = warehouseItemsService.getById(linkItemToWareHouseRequest.getItemId());
        if (warehouseItems == null) {
            throw new BusinessException(ErrorCode.ITEM_NOT_EXIST);
        }

        // 判断库存是否充足
        if (warehouse.getCapacity() < warehouseItems.getItemQuantity()) {
            throw new BusinessException(ErrorCode.WAREHOUSE_NOT_ENOUGH_CAPACITY);
        }

        // 更新仓库可用容量
        warehouse.setCapacity(warehouse.getCapacity() - warehouseItems.getItemQuantity());
        boolean update = this.updateById(warehouse);
        if (!update) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }

        // 新增库存关联关系
        warehouseItems.setWarehouseId(linkItemToWareHouseRequest.getWarehouseId());
        boolean updateItems = warehouseItemsService.updateById(warehouseItems);
        if (!updateItems) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }

        return true;
    }

    @Override
    public Page<WarehouseItemVO> getNotAllocatedItems(HttpServletRequest request, int pageNum, int pageSize) {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        HospitalVO hospitalInfo = getHospitalInfoByUser(loginUser);
        if (hospitalInfo == null) {
            throw new BusinessException(ErrorCode.HOSPITAL_NOT_EXIST);
        }

        // 根据医院ID查询未分配的库存
        QueryWrapper<WarehouseItems> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(WAREHOUSE_ID, null);
        queryWrapper.eq(HOSPITAL_ID, hospitalInfo.getId());
        Page<WarehouseItems> warehouseItemsPage = warehouseItemsService.page(new Page<>(pageNum, pageSize), queryWrapper);
        Page<WarehouseItemVO> warehouseItemVOPage = new Page<>();
        BeanUtils.copyProperties(warehouseItemsPage, warehouseItemVOPage);
        warehouseItemVOPage.setRecords(warehouseItemsPage.getRecords().stream().map(item -> {
            WarehouseItemVO warehouseItemVO = new WarehouseItemVO();
            BeanUtils.copyProperties(item, warehouseItemVO);
            return warehouseItemVO;
        }).toList());
        return warehouseItemVOPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean medicineTransferRequest(MedicineTransferRequest medicineTransferRequest, HttpServletRequest request) {
        // 获取登录用户信息
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        // 判断请求数量是否合法
        if (medicineTransferRequest.getQuantity() <= 0) {
            log.error("申请数量不能小于1");
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "申请数量不能小于1");
        }

        // 获取当前用户所属医院信息
        HospitalVO hospitalInfo = getHospitalInfoByUser(loginUser);
        if (hospitalInfo == null) {
            log.error(HospitalNotFound);
            throw new BusinessException(ErrorCode.HOSPITAL_NOT_EXIST, HospitalNotFound);
        }

        // 判断请求医院是否为当前用户的医院
        if (!Objects.equals(medicineTransferRequest.getToHospitalId(), hospitalInfo.getId())) {
            log.error("当前用户不是目标医院");
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "当前用户不是目标医院");
        }

        // 判断被调用医院是否存在
        HospitalVO toHospitalInfo = getHospitalInfoById(medicineTransferRequest.getToHospitalId());
        if (toHospitalInfo == null) {
            log.error("被调用医院不存在");
            throw new BusinessException(ErrorCode.HOSPITAL_NOT_EXIST, "被调用医院不存在");
        }

        // 判断请求药物是否存在
        WarehouseItems warehouseItems = getWarehouseItem(medicineTransferRequest);
        if (warehouseItems == null) {
            log.error("请求药物不存在");
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "请求药物不存在");
        }

        // 判断请求数量是否大于库存数量
        if (medicineTransferRequest.getQuantity() > warehouseItems.getItemQuantity()) {
            log.error("请求数量大于库存数量");
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "请求数量大于库存数量");
        }

        // 更新库存数量
        updateWarehouseItemQuantity(warehouseItems, medicineTransferRequest.getQuantity());

        // 新增调取记录
        saveMedicineTransferRecord(medicineTransferRequest);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean agreeMedicineTransferRequest(Long medicineTransferId) {
        Medicinetransfer medicinetransfer = medicinetransferService.getById(medicineTransferId);

        // 检查调取记录状态
        checkMedicineTransferStatus(medicinetransfer);

        // 根据药品名字找到药品
        WarehouseItems warehouseItems = findWarehouseItem(medicinetransfer);

        // 检查库存数量是否足够
        if (warehouseItems.getItemQuantity() < medicinetransfer.getQuantity()) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, QuantityNotEnough);
        }

        // 更新调取记录状态
        updateMedicineTransferStatus(medicinetransfer);

        // 更新库存数量
        updateWarehouseItemQuantity(warehouseItems, medicinetransfer.getQuantity());

        // 更新仓库库存
        updateWarehouseCapacity(warehouseItems.getWarehouseId(), medicinetransfer.getQuantity());

        return true;
    }

    /**
     * 检查调取记录状态
     * @param medicinetransfer 调取记录
     */
    private void checkMedicineTransferStatus(Medicinetransfer medicinetransfer) {
        if (medicinetransfer.getIsCompleted() == 1) {
            log.error(WareHouseRecordCompleted);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, WareHouseRecordCompleted);
        }
        if (medicinetransfer.getIsAuthorized() == 1) {
            log.error(WareHouseRecordAuthorized);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, WareHouseRecordAuthorized);
        }
    }

    /**
     * 根据药品名字找到药品
     * @param medicinetransfer 调取记录，包含药品名字和目标医院ID等信息
     * @return WarehouseItems 对应的仓库药品信息
     * @throws BusinessException 如果没有找到足够的药品库存，则抛出业务异常
     */
    private WarehouseItems findWarehouseItem(Medicinetransfer medicinetransfer) {
        // 根据药品名字和医院ID查询药品库存
        QueryWrapper<WarehouseItems> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ITEM_NAME, medicinetransfer.getItemName());
        queryWrapper.eq(HOSPITAL_ID, medicinetransfer.getToHospitalId());
        List<WarehouseItems> warehouseItemsList = warehouseItemsService.list(queryWrapper);

        // 在查询到的药品列表中，寻找足够数量的药品
        WarehouseItems warehouseItems = null;
        for (WarehouseItems item : warehouseItemsList) {
            if (item.getItemQuantity() >= medicinetransfer.getQuantity() && (warehouseItems == null || item.getItemQuantity() > warehouseItems.getItemQuantity())) {
                    warehouseItems = item;
            }
        }

        // 如果没有找到足够的药品库存，记录错误日志并抛出业务异常
        if (warehouseItems == null) {
            log.error(QuantityNotEnough);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, QuantityNotEnough);
        }

        // 返回找到的药品信息
        return warehouseItems;
    }


    /**
     * 更新调取记录状态
     * @param medicinetransfer 调取记录
     */
    private void updateMedicineTransferStatus(Medicinetransfer medicinetransfer) {
        medicinetransfer.setIsAuthorized(1);
        boolean update = medicinetransferService.updateById(medicinetransfer);
        if (!update) {
            log.error(UpdateWareHouseRecordFailed);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, UpdateWareHouseRecordFailed);
        }
    }

    /**
     * 更新仓库库存
     * @param warehouseId 仓库ID
     * @param quantity 数量
     */
    private void updateWarehouseCapacity(Long warehouseId, int quantity) {
        Warehouse warehouse = getWareHouseById(warehouseId);
        warehouse.setCapacity(warehouse.getCapacity() + quantity);
        boolean updateWarehouse = this.updateById(warehouse);
        if (!updateWarehouse) {
            log.error(UpdateWareHouseFailed);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, UpdateWareHouseFailed);
        }
    }

    /**
     * 获取当前用户所属医院信息
     * @param loginUser 登录用户
     * @return HospitalVO
     */
    private HospitalVO getHospitalInfoByUser(LoginUser loginUser) {
        GetHospitalInfoRequest getHospitalInfoRequest = new GetHospitalInfoRequest();
        getHospitalInfoRequest.setHospitalAccount(loginUser.getUserAccount());
        return userClient.getHospitalInfo(getHospitalInfoRequest);
    }

    /**
     * 获取医院信息
     * @param hospitalId 医院ID
     * @return HospitalVO
     */
    private HospitalVO getHospitalInfoById(Long hospitalId) {
        GetHospitalInfoRequest getHospitalInfoRequest = new GetHospitalInfoRequest();
        getHospitalInfoRequest.setHospitalId(hospitalId);
        return userClient.getHospitalInfo(getHospitalInfoRequest);
    }

    /**
     *
     * @param medicineTransferRequest 调取请求
     * @return WarehouseItems
     */
    private WarehouseItems getWarehouseItem(MedicineTransferRequest medicineTransferRequest) {
        QueryWrapper<WarehouseItems> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(ITEM_NAME, medicineTransferRequest.getItemName());
        queryWrapper.eq(HOSPITAL_ID, medicineTransferRequest.getFromHospitalId());
        queryWrapper.eq(WAREHOUSE_ID, medicineTransferRequest.getWarehouseId());
        return warehouseItemsService.getOne(queryWrapper);
    }

    private void updateWarehouseItemQuantity(WarehouseItems warehouseItems, int quantity) {
        warehouseItems.setItemQuantity(warehouseItems.getItemQuantity() - quantity);
        boolean update = warehouseItemsService.updateById(warehouseItems);
        if (!update) {
            log.error(UpdateWareHouseFailed);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, UpdateWareHouseFailed);
        }
    }

    private void saveMedicineTransferRecord(MedicineTransferRequest medicineTransferRequest) {
        Medicinetransfer medicinetransfer = new Medicinetransfer();
        BeanUtil.copyProperties(medicineTransferRequest, medicinetransfer);
        boolean save = medicinetransferService.save(medicinetransfer);
        if (!save) {
            log.error(AddWareHouseFailed);
            throw new BusinessException(ErrorCode.OPERATION_ERROR, AddWareHouseFailed);
        }
    }



    /**
     * 通过仓库ID获取仓库信息
     *
     * @param wareId 仓库ID
     * @return 存在返回true，不存在返回false
     */
    public Warehouse getWareHouseById(Long wareId) {
        Warehouse warehouse = this.getById(wareId);
        if (warehouse == null) {
            throw new BusinessException(ErrorCode.WAREHOUSE_NOT_EXIST);
        }
        return warehouse;
    }
}




